﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Scavenger
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
   
        Character player;
        Pointer pointer;

        MouseState mouseState = new MouseState();

        Texture2D projectileTexture;
        List<Projectile> projectiles;
        TimeSpan fireTime, previousFireTime = TimeSpan.FromSeconds(0);

        VectorStuff.Vector line;
        VectorStuff.Vector line2;
        VectorStuff.Vector vector;
        DrawPrimitives screenLine;
        DrawPrimitives screenLine2;
        DrawPrimitives projetionLine;

        SpriteFont guiFont;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            //graphics.ToggleFullScreen();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            player = new Character();
            pointer = new Pointer();
            projectiles = new List<Projectile>();

            line = new VectorStuff.Vector(Vector2.Zero, new Vector2(1, 1));
            line2 = new VectorStuff.Vector(Vector2.Zero, new Vector2(1, 1));

            vector = new VectorStuff.Vector(Vector2.Zero, Vector2.Zero);
            screenLine = new DrawPrimitives();
            screenLine.Initialize(line, new BasicPrimitives(GraphicsDevice));
            screenLine2 = new DrawPrimitives();
            screenLine2.Initialize(line2, new BasicPrimitives(GraphicsDevice));
            projetionLine = new DrawPrimitives();
            projetionLine.Initialize(vector, new BasicPrimitives(GraphicsDevice));
            fireTime = TimeSpan.FromSeconds(.15f);

            Mouse.SetPosition(200, 200);
                                                   
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);


            // Player initialization
            Vector2 position = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X,
                GraphicsDevice.Viewport.TitleSafeArea.Y + GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
            Animation playerAnimation = new Animation();

            playerAnimation.Initialize(Content.Load<Texture2D>("playerStrip"), position,
                40, 40, 4, 60, Color.White, 1f, true);

            player.Initialize(position, playerAnimation, 100, 0);

            // Pointer initialization
            pointer.Initialize(Content.Load<Texture2D>("pointer"));

            // Projectile initialization
            projectileTexture = Content.Load<Texture2D>("projectile");
            
            // GUI font
            guiFont = Content.Load<SpriteFont>("guiFont");
           
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            MouseState oldState = mouseState;
            mouseState = Mouse.GetState();

            pointer.Update(gameTime, mouseState);
            player.Update(gameTime, keyboardState, pointer);
            UpdateProjectiles();
                        
            // Make sure that the player does not go out of bounds
            player.Position.X = MathHelper.Clamp(player.Position.X, 25, GraphicsDevice.Viewport.Width + player.Width / 2);
            player.Position.Y = MathHelper.Clamp(player.Position.Y, 25, GraphicsDevice.Viewport.Height + player.Height / 2);
            
            // Fires projectiles
            if (pointer.State.LeftButton == ButtonState.Pressed && gameTime.TotalGameTime - previousFireTime > fireTime)
            {
                previousFireTime = gameTime.TotalGameTime;
                AddProjectile(player);
            }

            if (keyboardState.IsKeyDown(Keys.E))
            {
                line.Update(pointer.Position + new Vector2(pointer.Width / 2, pointer.Height / 2), "Start");
            }

            if (keyboardState.IsKeyDown(Keys.R))
            {
                line.Update(pointer.Position + new Vector2(pointer.Width / 2, pointer.Height / 2), "End");
            }

            if (pointer.State.RightButton == ButtonState.Pressed && oldState.RightButton == ButtonState.Released)
            {
                line2.Update(pointer.Position + new Vector2(pointer.Width / 2, pointer.Height / 2), "Start");
            }

            if (pointer.State.RightButton == ButtonState.Pressed)
            {
                line2.Update(pointer.Position + new Vector2(pointer.Width / 2, pointer.Height / 2), "End");
            }

            screenLine.UpdateTexture(line);
            screenLine2.UpdateTexture(line2);

            vector.Update(pointer.Position + new Vector2(pointer.Width / 2, pointer.Height / 2), "Start");
            vector.Update(VectorMath.Intersection(line2, line), "End");
            projetionLine.UpdateTexture(vector);

            // Updates player animation
            player.Graphic.Position = player.Position;
            player.Graphic.Update(gameTime);
            
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.SkyBlue);
            spriteBatch.Begin();

            player.Draw(spriteBatch);
            pointer.Draw(spriteBatch);

            for (int i = 0; i < projectiles.Count; i++)
                projectiles[i].Draw(spriteBatch);

            //Conrads comment out if it is in your way =)
            screenLine.Draw(spriteBatch);
            screenLine2.Draw(spriteBatch);
            projetionLine.Draw(spriteBatch);
            spriteBatch.DrawString(guiFont, "Intersection: " + VectorMath.Intersection(line2, line),
                                        new Vector2(0, 118), Color.White);

            // GUI -- Most of this stuff goes when shit work
            spriteBatch.DrawString(guiFont, "Player: " + (player.Position.X - player.Width / 2) + ", " + 
                (player.Position.Y - player.Height / 2), Vector2.Zero, Color.White);
            spriteBatch.DrawString(guiFont, "Rotation: " + (player.Rotation * 180 / MathHelper.Pi), 
                new Vector2(0, 18), Color.White);
            spriteBatch.DrawString(guiFont, "Mouse: " + (pointer.Position.X + pointer.Width / 2) + ", " + 
                (pointer.Position.Y + pointer.Height / 2), new Vector2(0, 36), Color.White);
            spriteBatch.DrawString(guiFont, "Projectiles: " + projectiles.Count, new Vector2(0, 54), Color.White);



            if (projectiles.Count > 0)
                spriteBatch.DrawString(guiFont, " - dY = " + projectiles.Last().dY + "\n - dX = " + projectiles.Last().dX,
                    new Vector2(0, 70), Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }

        private void AddProjectile(Character agent)
        {
            Projectile projectile = new Projectile();
            projectile.Initialize(GraphicsDevice.Viewport, projectileTexture, agent.Position, agent.Rotation);
            projectiles.Add(projectile);
        }

        private void UpdateProjectiles()
        {
            for (int i = 0; i < projectiles.Count; i++)
            {
                projectiles[i].Update();

                if (!projectiles[i].Active)
                {
                    projectiles.RemoveAt(i);
                }
            }
        }

    }
}
